﻿using System;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
using GiveAQuiz.Data;
using GiveAQuiz.Web.Membership;
using GiveAQuiz.Web.Models;
using GiveAQuizSite.Controllers;
using Moq;
using MvcContrib.TestHelper;
using NUnit.Framework;

namespace GiveAQuizSite.Tests.Controllers
{
  [TestFixture]
  public class QuizControllerTest : AuthenticationControllerTest
  {
    public Mock<IMembershipService> MockMembershipService
    {
      get;
      private set;
    }

    public QuizController QuizController
    {
      get;
      private set;
    }

    [TestFixtureSetUp]
    public void FixtureSetUp()
    {
      MockRepository = new Mock<IQuizRepository>();
      MockMembershipService = new Mock<IMembershipService>();
      MockMembershipService.SetupGet(m => m.CurrentUser).Returns(MockUser.Object);
    }

    [SetUp]
    public void TestSetUp()
    {
      QuizController = new QuizController(MockRepository.Object, MockMembershipService.Object);
      QuizController.ControllerContext = new ControllerContext(MockHttpContext.Object, new RouteData(), QuizController);
    }

    [Test]
    public void Index_calls_QuizRespository_GetUserQuizDefinitions_for_current_user() 
    {
      var view = QuizController.Index();
      Guid userId = (Guid)MockUser.Object.ProviderUserKey;
      // verify the call was made
      MockRepository.Verify(r => r.GetUserQuizDefinitions(userId));
    }

    [Test]
    public void Index_returns_Model_instance_of_IEnumerable_of_QuizDefintion()
    {
      ViewResult view = QuizController.Index() as ViewResult;
      view.AssertViewRendered().WithViewData<IEnumerable<QuizDefinition>>();
    }

    [Test]
    public void Index_returns_Model_populated_from_QuizRepository_GetUserQuizDefinitions()
    {
      var quizzes = CreateQuizDefinitions();
      MockRepository.Setup(qr => qr.GetUserQuizDefinitions(It.IsAny<Guid>())).Returns(quizzes);

      // call the controller
      ViewResult view = QuizController.Index() as ViewResult;

      view.AssertViewRendered();

      // get the Model for the View
      var model = view.ViewData.Model as IEnumerable<QuizDefinition>;
      Assert.IsNotNull(model);      

      Assert.Greater(model.Count(), 0);
      Assert.AreEqual(quizzes.Count(), model.Count());

      // make sure all the quizzes in the model are there
      foreach (var modelQuiz in model)
      {
        Assert.IsNotNull(quizzes.FirstOrDefault(q => q.Id == modelQuiz.Id));
      }
    }

    [Test]
    public void Delete_calls_QuizRepository_DeleteQuiz()
    {
      int quizId = 5;
      var view = QuizController.Delete(quizId);

      // verify call was made
      MockRepository.Verify(qr => qr.DeleteQuiz(quizId));
    }

    [Test]
    public void Delete_redirects_to_Index_action()
    {
      int quizId = 5;

      RedirectToRouteResult result = QuizController.Delete(quizId) as RedirectToRouteResult;

      Assert.IsNotNull(result);

      result.AssertActionRedirect().ToAction("Index");
    }

    [Test]
    public void Pick_Get_should_return_Pick_view()
    {
      // Act
      ViewResult result = (ViewResult) QuizController.Pick();

      // Assert
      result.AssertViewRendered();
    }

    [Test]
    public void Pick_Post_should_return_view_if_ModelState_IsValid_is_false()
    {
      // add an error
      QuizController.ModelState.AddModelError("QuizPassphrase", "Dummy");

      var model = new QuizPickerViewModel {QuizPassphrase = null};

      // Act
      var result = QuizController.Pick(model) as ViewResult;

      // Assert
      result.AssertViewRendered();
      Assert.IsFalse(result.ViewData.ModelState.IsValid);
    }

    [Test]
    public void Pick_Post_should_call_QuizRepository_GetQuizByPassphrase()
    {
      // Arrange
      var model = new QuizPickerViewModel { QuizPassphrase = "letme1n" };
      var quiz = new Quiz {Id = 1};
      MockRepository.Setup(r => r.GetQuizByPassphrase(model.QuizPassphrase)).Returns(quiz).Verifiable();
      
      // Act
      var result = QuizController.Pick(model) as RedirectToRouteResult;

      // Assert
      MockRepository.VerifyAll();
    }

    [Test]
    public void Pick_Post_should_redirect_to_Take_if_quiz_is_found() 
    {
      // Arrange
      var model = new QuizPickerViewModel { QuizPassphrase = "letme1n" };
      var quiz = new Quiz { Id = 1 };
      MockRepository.Setup(r => r.GetQuizByPassphrase(model.QuizPassphrase)).Returns(quiz).Verifiable();

      // Act
      var result = QuizController.Pick(model) as RedirectToRouteResult;

      // Assert
      result.AssertActionRedirect().ToAction("Take").WithParameter("id", quiz.Id);
    }

    private IEnumerable<QuizDefinition> CreateQuizDefinitions()
    {
      Random rand = new Random();
      int size = rand.Next(1, 10);

      IList<QuizDefinition> quizzes = new List<QuizDefinition>();

      // create 1-10 random quizzes
      for (var i = 1; i <= size; i++)
      {
        quizzes.Add(
          new QuizDefinition
            {
              Id = i,
              QuizName = String.Format("Quiz {0}", i),
              Owner = (Guid)MockUser.Object.ProviderUserKey,
              Description = "Another Quiz"
            });
      }
      return quizzes;
    }
  }
}
